package com.abing.chatRoom.service.impl;

import com.abing.chatRoom.common.ErrorCode;
import com.abing.chatRoom.exception.BusinessException;
import com.abing.chatRoom.mapper.TeamMapper;
import com.abing.chatRoom.model.VO.UserVO;
import com.abing.chatRoom.model.domain.Team;
import com.abing.chatRoom.model.domain.User;
import com.abing.chatRoom.model.domain.UserTeam;
import com.abing.chatRoom.model.dto.TeamQuery;
import com.abing.chatRoom.model.enums.TeamStatusEnum;
import com.abing.chatRoom.model.request.TeamJoinRequest;
import com.abing.chatRoom.model.request.TeamQuitRequest;
import com.abing.chatRoom.model.request.TeamUpdateRequest;
import com.abing.chatRoom.service.UserTeamService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.abing.chatRoom.model.VO.TeamUserVO;
import com.abing.chatRoom.service.TeamService;
import com.abing.chatRoom.service.UserService;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.TimeUnit;

/**
* @author abing
* @description 针对表【team(队伍)】的数据库操作Service实现
* @createDate 2024-08-09 15:45:05
*/
@Service
public class TeamServiceImpl extends ServiceImpl<TeamMapper, Team>
    implements TeamService {
    @Resource
    private UserTeamService userTeamService;
    @Resource
    private UserService userService;

    @Resource
    private RedissonClient redissonClient;
    @Resource
    private  TeamMapper teamMapper;
    @Transactional(rollbackFor = Exception.class)
    @Override
    public long addTeam(Team team, User loginUser) {
        //1
        //请求参数是否为空？
        if(team==null){
            throw new BusinessException(ErrorCode.NULL_ERROR);
        }
        //2
        //是否登录，未登录不允许创建
        if(loginUser==null){
            throw new BusinessException(ErrorCode.NO_AUTH);
        }
        final long userId = loginUser.getId();
        //3
        //校验信息
        //a
        //队伍人数 > 1 且 <= 20
        Integer max = Optional.ofNullable(team.getMaxNum()).orElse(0);
        if(max<=1||max>20){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"队伍人数不满足要求");
        }
        //b
        //队伍标题 <= 20
        String teamName = team.getName();
        if(teamName.length()>20|| StringUtils.isBlank(teamName)){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"名字长度不满足要求");
        }
        //c
        //描述 <= 512
        String teamDescription = team.getDescription();
        if(StringUtils.isNotBlank(teamDescription) &&teamDescription.length()>512){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"描述长度不满足要求");
        }
        //d
        //status 是否公开（int）不传默认为 0（公开）
        int status = Optional.ofNullable(team.getStatus()).orElse(0);
        TeamStatusEnum statusEnum = TeamStatusEnum.getEnumByValue(status);
        if (statusEnum == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "队伍状态不满足要求");
        }
        //e
        //如果 status 是加密状态，一定要有密码，且密码 <= 32
        String password = team.getPassword();
        if(TeamStatusEnum.SECRET.equals(statusEnum)){
            if (StringUtils.isBlank(password) || password.length() > 32) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "密码设置不正确");
            }
        }
        //f
        //超时时间 > 当前时间
        Date expireTime = team.getExpireTime();
        if (new Date().after(expireTime)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "超时时间 > 当前时间");
        }
        //g
        //校验用户最多创建 5 个队伍
        QueryWrapper<Team> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("userId", userId);
        long hasTeamNum = this.count(queryWrapper);
        if (hasTeamNum >= 5) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户最多创建 5 个队伍");
        }
        //4. 插入队伍信息到队伍表
        team.setTeamId(null);
        team.setUserId(userId);
        boolean result = this.save(team);
        Long teamId = team.getTeamId();
        if (!result || teamId == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "创建队伍失败");
        }
        //5. 插入用户 => 队伍关系到关系表
        UserTeam userTeam = new UserTeam();
        userTeam.setUserId(userId);
        userTeam.setTeamId(teamId);
        userTeam.setJoinTime(new Date());
        result = userTeamService.save(userTeam);
        if (!result) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "创建队伍失败");
        }
        return teamId;
    }

    @Override
    public List<TeamUserVO> listTeams(TeamQuery teamQuery, boolean isAdmin) {
        QueryWrapper<Team> queryWrapper = new QueryWrapper<>();
        //组合查询条件
        if(teamQuery!=null) {
            Long id = teamQuery.getUserId();
            if(id!=null&&id>0){
                queryWrapper.eq("teamId",id);
            }
            List<Long> idList = teamQuery.getIdList();
            if(CollectionUtils.isNotEmpty(idList)){
                queryWrapper.in("teamId",idList);
            }
            String searchText = teamQuery.getSearchText();
            if(StringUtils.isNotBlank(searchText)){
                queryWrapper.and(qw -> qw.like("name", searchText).or().like("description", searchText));
            }
            String name = teamQuery.getName();
            if(StringUtils.isNotBlank(name)){
                queryWrapper.like("name",name);
            }
            String description = teamQuery.getDescription();
            if(StringUtils.isNotBlank(description)){
                queryWrapper.like("description",description);
            }
            //查询最大人数相等
            Integer maxNum = teamQuery.getMaxNum();
            if(maxNum!=null&&maxNum>0){
                queryWrapper.eq("maxNum",maxNum);
            }
            //根据创建人来查询
            Long userId = teamQuery.getUserId();
            if(userId!=null){
                queryWrapper.eq("userId",userId);
            }
            //根据状态查询
            Integer status = teamQuery.getStatus();
            TeamStatusEnum statusEnum = TeamStatusEnum.getEnumByValue(status);
            if(statusEnum==null){
                statusEnum=TeamStatusEnum.PUBLIC;
            }
            if(!isAdmin&& statusEnum.equals(TeamStatusEnum.PRIVATE)){
                throw new BusinessException(ErrorCode.NO_AUTH);
            }
            queryWrapper.eq("status",statusEnum.getValue());
        }
        //不展示过期的队伍
        queryWrapper.and(qw->qw.gt("expireTime",new Date()).or().isNull("expireTime"));

        List<Team> list = this.list(queryWrapper);
        if(list==null){
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        if(CollectionUtils.isEmpty(list)){
            return new ArrayList<>();
        }
        List<TeamUserVO> teamUserVOList = new ArrayList<>();
        //关联查询创建人的用户信息
        for(Team team:list) {
            Long userId = team.getUserId();
            if(userId==null){
                continue;
            }
            User user = userService.getById(userId);
            TeamUserVO teamUserVO = new TeamUserVO();
            BeanUtils.copyProperties(team,teamUserVO);
            //脱敏用户信息
            if(user!=null){
                UserVO userVO = new UserVO();
                BeanUtils.copyProperties(user,userVO);
                teamUserVO.setCreateUser(userVO);
            }
            teamUserVOList.add(teamUserVO);
        }
        return teamUserVOList;
    }

    @Override
    public boolean updateTeam(TeamUpdateRequest teamUpdateRequest, User loginUser) {
        //1
        //判断请求参数是否为空
        if(teamUpdateRequest==null){
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        //2
        //查询队伍是否存在
        Long id = teamUpdateRequest.getTeamId();
        if(id==null||id<=0){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"id:"+id);
        }
        Team teamOld = this.getById(id);
        if(teamOld==null){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"队伍不存在");
        }
        //3
        //只有管理员或者队伍的创建者可以修改
        if(!userService.isAdmin(loginUser)&& !teamOld.getUserId().equals(loginUser.getId())){
            throw new BusinessException(ErrorCode.NO_AUTH);
        }
        //4
        //如果用户传入的新值和老值一致，就不用 update 了（可自行实现，降低数据库使用次数）
        //5
        //如果队伍状态改为加密，必须要有密码
        TeamStatusEnum enumStatus = TeamStatusEnum.getEnumByValue(teamOld.getStatus());
        if(enumStatus.equals(TeamStatusEnum.SECRET)){
            if(StringUtils.isNotBlank(teamUpdateRequest.getPassword())){
                throw new BusinessException(ErrorCode.PARAMS_ERROR,"加密房间必须设置密码");
            }
        }
        //6
        //更新成功
        Team team = new Team();
        BeanUtils.copyProperties(teamUpdateRequest,team);
        return this.updateById(team);
    }

    @Override
    public boolean joinTeam(TeamJoinRequest teamJoinRequest, User loginUser) {
        if(teamJoinRequest==null){
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        Long teamId = teamJoinRequest.getTeamId();
        if(teamId==null||teamId<=0){
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        Team team = this.getById(teamId);
        if(team==null){
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        //队伍必须存在，只能加入未满、未过期的队伍
        Date expireTime = team.getExpireTime();
        if(expireTime==null||expireTime.before(new Date())){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"队伍已经过期");
        }
        //禁止加入私有的队伍
        TeamStatusEnum enumStatus = TeamStatusEnum.getEnumByValue(team.getStatus());
        if(enumStatus.equals(TeamStatusEnum.PRIVATE)){
            throw new BusinessException(ErrorCode.NO_AUTH,"禁止加入私有队伍");
        }
        //如果加入的队伍是加密的，必须密码匹配才可以
        String password = teamJoinRequest.getPassword();
        if(TeamStatusEnum.SECRET.equals(enumStatus)&&!team.getPassword().equals(password)){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"密码错误");
        }
        //用户最多加入 5 个队伍
        long id = loginUser.getId();
        QueryWrapper<UserTeam> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("userId",id);
        long count = userTeamService.count(queryWrapper);
        if(count>5){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"最多可以加入5个队伍");
        }

        RLock rLock = redissonClient.getLock("abing:precachejob:docache:lock");
        try {
            while(true){
                if(rLock.tryLock(0,-1, TimeUnit.MILLISECONDS)){
                    //不能重复加入已加入的队伍
                    queryWrapper=new QueryWrapper<>();
                    queryWrapper.eq("userId",id);
                    queryWrapper.eq("teamId",teamId);
                    long hasUserJoinTeam = userTeamService.count(queryWrapper);
                    if(hasUserJoinTeam>0){
                        throw new BusinessException(ErrorCode.PARAMS_ERROR,"不能重复加入已加入的队伍");
                    }

                    //已加入队伍的人数
                    queryWrapper=new QueryWrapper<>();
                    queryWrapper.eq("teamId",teamId);
                    long teamHasJoinNum = userTeamService.count(queryWrapper);
                    if(teamHasJoinNum>=team.getMaxNum()){
                        throw new BusinessException(ErrorCode.PARAMS_ERROR,"队伍已满");
                    }
                    //新增队伍 - 用户关联信息
                    UserTeam userTeam = new UserTeam();
                    userTeam.setTeamId(teamId);
                    userTeam.setUserId(id);
                    userTeam.setJoinTime(new Date());
                    return userTeamService.save(userTeam);}
            }
        } catch (InterruptedException e) {
            log.error("doCacheRecommendUser error", e);
            return false;
        } finally {
            //只能释放自己的锁
            if(rLock.isHeldByCurrentThread()){
                System.out.println("unLock: " + Thread.currentThread().getId());
                rLock.unlock();
            }

        }

    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean quitTeam(TeamQuitRequest teamQuitRequest, User loginUser) {
        //1
        // 校验请求参数
        if(teamQuitRequest==null){
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        //2
        // 校验队伍是否存在
        Long teamId = teamQuitRequest.getTeamId();
        if(teamId==null||teamId<=0){
            throw new BusinessException(ErrorCode.NULL_ERROR);
        }
        Team team = this.getById(teamId);
        if(team==null){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"队伍不存在");
        }
        //3
        // 校验我是否已加入队伍
        long id = loginUser.getId();
        UserTeam userTeam = new UserTeam();
        userTeam.setTeamId(teamId);
        userTeam.setUserId(id);
        QueryWrapper<UserTeam> queryWrapper = new QueryWrapper<>(userTeam);
        long count = userTeamService.count(queryWrapper);
        if(count==0){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"未加入该队伍");
        }
        long userByTeamId = this.countTeamUserByTeamId(teamId);
        //4
        // 如果队伍
        //a
        // 只剩一人，队伍解散
        if(userByTeamId==1){
            this.removeById(teamId);
        }else{
            //b
            // 还有其他人
            //ⅰ
            // 如果是队长退出队伍，权限转移给第二早加入的用户 —— 先来后到
            if(id==team.getUserId()){
                QueryWrapper<UserTeam> userTeamQueryWrapper = new QueryWrapper<>();
                userTeamQueryWrapper.eq("teamId",teamId);
                //只用取 id 最小的 2 条数据
                userTeamQueryWrapper.last("order by id asc limit 2");
                List<UserTeam> userTeamList = userTeamService.list(userTeamQueryWrapper);
                if(CollectionUtils.isEmpty(userTeamList)||userTeamList.size()<=1){
                    throw new BusinessException(ErrorCode.SYSTEM_ERROR);
                }
                UserTeam nextUserTeam = userTeamList.get(1);
                Long nextUserTeamUserId = nextUserTeam.getUserId();
                //更新当前队伍的队长
                Team updateTeam = new Team();
                updateTeam.setTeamId(teamId);
                updateTeam.setUserId(nextUserTeamUserId);
                boolean result = this.updateById(updateTeam);
                if(!result){
                    throw new BusinessException(ErrorCode.SYSTEM_ERROR,"更新队长失败");
                }
            }
        }
        //   	 ⅱ.  非队长，自己退出队伍
        return userTeamService.remove(queryWrapper);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean deleteTeam(long teamId, User loginUser) {
        //校验请求参数
        if(teamId<=0){
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        //校验队伍是否存在
        Team team = this.getTeamById(teamId);
        //校验你是不是队伍的队长
        if(!loginUser.getId().equals(team.getUserId())){
            throw new BusinessException(ErrorCode.NO_AUTH);
        }
        //移除所有加入队伍的关联信息
        QueryWrapper<UserTeam> queryWrapper = new QueryWrapper<UserTeam>();
        queryWrapper.eq("teamId",teamId);
        boolean remove = userTeamService.remove(queryWrapper);
        if(!remove){
            throw new BusinessException(ErrorCode.SYSTEM_ERROR,"删除队伍关联信息失败");
        }
        //删除队伍
        return this.removeById(teamId);
    }

    private long countTeamUserByTeamId(long teamId) {
        QueryWrapper<UserTeam> userTeamQueryWrapper = new QueryWrapper<>();
        userTeamQueryWrapper.eq("teamId", teamId);
        return userTeamService.count(userTeamQueryWrapper);
    }

    public Team getTeamById(Long teamId){
        if(teamId==null||teamId<=0){
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        QueryWrapper<Team> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("teamId",teamId);
        Team team = teamMapper.selectOne(queryWrapper);
        if(team==null){
            throw new BusinessException(ErrorCode.NULL_ERROR,"队伍不存在");
        }
        return team;
    }
}




